/*
 * Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
 *
 * Licensed under the Mulan PSL v2.
 * You can use this file according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of the License at
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
 * FOR MORE DETAILS.
 */

#pragma once

#include "Utility/Logging/SGLogger.h"

#include "DBManager/Database/CacheHelper.h"
#include "DBManager/Repository/HDF5/Base/RepositoryBase.h"

SG_DBMANAGER_HDF5_NAMESPACE_OPEN

/**
 * @brief 用于缓存数据的结构体。
 */

template <typename T>
struct MainCache
{
    std::size_t    m_limitSize{ 0 };   ///< 最大缓存数量
    std::vector<T> m_writeStorage{};   ///< 写入缓存的数据
    std::string    m_readCacheKey{};   ///< 当前读取缓存在 CachePool 中的键
    std::size_t    dataMinIndex{ 0 };  ///< Read缓存的最小索引
    std::size_t    dataMaxIndex{ 0 };  ///< Read缓存的最大索引
};

template <typename T>
class DBManager_DECLSPEC CacheRepositoryBase : public RepositoryBase
{
  public:
    explicit CacheRepositoryBase (HDF5Database& database) : RepositoryBase (database), m_cacheHelper (database) {};

    virtual ~CacheRepositoryBase () = default;

    /**
     * @brief   : 读缓存
     * @param   : loadIndex
     * @author  : wxc
     * @date    : 2024.11.01
     */
    virtual std::vector<T>* LoadReadCache (std::size_t loadIndex) = 0;

    /**
     * @brief   : 转存缓存区数据
     * @author  : wxc
     * @date    : 2024.11.01
     */
    virtual void DumpWriteCahce () = 0;

    /**
     * @brief 纯虚函数，用于对数据进行排序，需由派生类实现。
     *
     * @return 排序是否成功
     */
    virtual void SortData () = 0;

    /**
     * @brief   : 重写索引数据
     * @param   : datas
     * @author  : wxc
     * @date    : 2024.11.01
     */
    virtual void RewriteIndexData (std::vector<T>& datas)
    {
        std::vector<SG::DataStructure::Common::I64> ids;
        ids.reserve (datas.size ());
        for (auto& data : datas)
        {
            // 如果有sid 就是用sid
            if constexpr (has_sId<T>::value)
            {
                ids.push_back (data.m_sId);
            }
            // 如果有id 就是用id
            else if constexpr (has_id<T>::value)
            {
                ids.push_back (data.m_id);
            }
        }
        auto indexDataset = GetDataset (IndexDataset);
        indexDataset.resize ({ ids.size () });
        indexDataset.write (ids);
    }

    virtual void Sort ()
    {
        // 如果已有的数据未排序
        if (!GetMainDatasetInfo ().IsSequential ())
        {
            // 将写的数据先dump
            if (!m_mainCache.m_writeStorage.empty ())
            {
                this->DumpWriteCahce ();
            }

            if (this->GetMainDatasetInfo ().IsCreate ())
            {
                SortData ();
            }

            GetMainDatasetInfo ().SetIsSequential (true);

            // 清除当前的读取缓存键和索引信息
            if (!m_mainCache.m_readCacheKey.empty ())
            {
                GetDatabase ().GetCachePool ().Remove (m_mainCache.m_readCacheKey);
            }

            m_mainCache.dataMinIndex = 0;
            m_mainCache.dataMaxIndex = 0;
        }
    }

    virtual constexpr int64_t GetDatasetCacheSize () const
    {
        return DATASET_CACHE_SIZE;
    }

    virtual void InitDataset () override
    {
        RepositoryBase::InitDataset ();

        if (m_mainCache.m_limitSize == 0)
            m_mainCache.m_limitSize = GetDatasetCacheSize () / GetMainDatasetInfo ().GetDataSize ();

        m_mainCache.m_readCacheKey = GetMainDatasetInfo ().GetPath () + "_ReadCache";
        m_indexCache.cacheKey      = GetMainDatasetInfo ().GetPath () + "_IndexCache";
    }

    // 加载主表的原始表数据

    template <typename MT>
    void LoadMainMetadata (std::size_t index, std::vector<MT>& data)
    {
        // 从主表里哪部分开始取数据
        std::size_t beginIndex = 0;
        // 取多少条
        std::size_t length = 0;
        GetMainDatasetInfo ().CalcIndexBeginAndLength (index, _OUT beginIndex, _OUT length, GetDatasetCacheSize ());
        GetDataset (MainDataset).select ({ beginIndex }, { length }).read (data);

        // 更新缓存状态
        GetMainCache ().dataMinIndex = beginIndex;
        GetMainCache ().dataMaxIndex = beginIndex + length;
    }

    /// @brief 添加之后的事件
    virtual void AfterAdd (T& entity)
    {}

    MainCache<T>& GetMainCache ()
    {
        return m_mainCache;
    }

    IndexCache& GetIndexCache ()
    {
        return m_indexCache;
    }

  private:
    MainCache<T> m_mainCache;   ///< 表单缓存信息
    IndexCache   m_indexCache;  ///< 索引缓存
  protected:
    SG::DBManager::CacheHelper m_cacheHelper;
};

SG_DBMANAGER_HDF5_NAMESPACE_CLOSE
